home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-20
/
rs0422.zip
/
LEVEL2
/
AX25L2.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-24
|
23KB
|
766 lines
/* AX25 Level 2 interface -- KE3Z 08/9/87 */
#include "buffer.h"
#include "iface.h"
#include "timer.h"
#include "ax25.h"
#include "ax25l2.h"
#include "netuser.h"
#include "data.h"
#include "hdlctl.h"
struct axcb *links; /* Main should init this = NULL; */
int control;
struct ax25_addr adr[9];
unsigned char swpos;
unsigned char numadr, numadrm; /* Number of addresses (callsigns) */
extern unsigned char digi;
extern unsigned char node_addr[16];
extern struct ax25_addr L3CALL[1], L3DIGI[1];
extern struct ax25_parms *l3parms;
int l3_st_up(), l2_window();
void level3(), NULLFCN();
/* lookup_axcb -- searches through the list of axcbs for a match to the
* input parameters and returns a pointer to the first matching axcb.
* returns NULL if no match found.
*/
struct axcb *
lookup_axcb(laddr, raddrx, iface, alenx)
struct ax25_addr *laddr; /* Local address to match */
struct ax25_addr raddrx[]; /* Remote address to match */
struct interface *iface; /* Interface to match */
int alenx;
{
register struct axcb *axcb;
int callcmp();
static int i, j;
static struct ax25_addr *raddr; /* Remote address to match */
static int alen;
alen=alenx;
if ((raddr=raddrx) == NULL || laddr == NULL) return NULL;
for (axcb = links; axcb != NULL; axcb = axcb->next) {
if (callcmp(laddr, &axcb->myaddr) && /* MYCALL match */
(iface == axcb->iface) && /* Interface matches */
(axcb->alen == alen) && /* Path same length */
(callcmp(raddr,axcb->path))) /* Src matches */ {
j=alen;
for (i=1;i<alen;i++) /* Check path */ {
j--;
if ((((raddr[j].ssid & (SSID | REPEATED)) ^ REPEATED)
!= (axcb->path[i].ssid & (SSID | REPEATED)))
|| !callcmp(&raddr[alen-i],&axcb->path[i]))
goto no_match;
/* The above insures the REPEATED bits are
right (the path in axcb has them toggled) */
}
return axcb;
}
no_match: continue;
}
return NULL;
}
/* ax25l2 -- handler of received AX.25 frames. */
struct datastr *
ax25l2(ifacex, bpx) /* If it returns the frame then free it */
struct interface *ifacex; /* Interface frame was received on */
struct datastr *bpx; /* Received frame */
{
static struct interface *iface; /* Interface frame was received on */
static struct datastr *bp; /* Received frame */
register struct axcb *axcb;
static char rxversion;
static unsigned char *chr, *chx;
static unsigned char iscmd;
static int ctl;
static struct change *ch;
static struct change *state_tables[3][2][2] = {
{ {rr_resp, rr_respf}, {rr_cmd, rr_cmdp} },
{ {rnr_resp, rnr_respf}, {rnr_cmd, rnr_cmdp} },
{ {rr_resp, rr_respf}, {rr_resp, rr_cmdp} }
};
static struct change *state_tableu[6] =
{ NULL, disc_cmd, ua_resp, frmr_resp, dm_resp, sabm_cmd };
struct datastr *proci(), *setaddr();
int callcmp();
struct axcb *l2conreq();
iface=ifacex;
bp=bpx;
iscmd=0;
ch=NULL;
/* Save Buffer start address incase this is a digipeat request */
chr = bp->rdata;
/* Move the address field into local storage */
digi=0;
if ((numadr=get_addr(bp, adr, FALSE)) == 0) return NULL;
control = *bp->rdata;
ctl = decode_ctl(control);
/* Restore the buffer start address so we can return a whole frame
if we can't handle it */
chx = bp->rdata;
bp->rdata = chr;
/* Check for valid address length, Ignore UI's and wrong PID */
if ((numadr > 7) || (numadr < 2)) return bp;
if (numadr == 3) {
if (digi) /* Not repeated yet */ {
if (callcmp(&adr[2],&L3DIGI[0])) {
(*iface->send)(iface,bp);
return NULL;
}
else return bp; /* Not for me */
}
}
swpos = 0;
if (ctl == ctl_UI) return bp; /* Ignore UI's */
if (callcmp(&adr[0],&L3CALL[0])) swpos = 1;
if (callcmp(&adr[1],&L3CALL[0])) return bp; /* I sent it */
if (digi) {
if (callcmp(&adr[digi],&L3CALL[0]) ||
callcmp(&adr[digi],&L3DIGI[0])) swpos = digi+1;
}
numadrm = numadr-1;
if ((axcb=lookup_axcb(&adr[0],&adr[1],iface,numadrm)) == NULL) {
if ( !swpos || (ctl == ctl_DM) ) return bp;
if (ctl == ctl_SABM) axcb=l2conreq(iface);
if (axcb == EOF) return bp; /* To us, but ignore */
if (axcb == NULL) {
/* We get here if there is no link or against our rules */
axcb=new_link();
axcb->iface = iface;
callcpy(&axcb->myaddr, &adr[0]);
setpath(axcb, &adr[1], 1, numadrm);
(*iface->send)(iface,setaddr(axcb,DM,0) );
free(axcb);
return bp;
}
}
bp->rdata = chx; /* Restore buffer to the ctl field */
(void)bgetch(&bp); /* Fetch the control field */
/* Determine the protocol version of the received frame */
if ((adr[0].ssid ^ adr[1].ssid) & C)
rxversion = V2;
else
rxversion = V1;
/* Determine if received frame is command or response */
if ((adr[0].ssid & C) && !(adr[1].ssid & C)) iscmd = 1;
/* Reject any non-I frame with an I field except FRMR type */
if (ctl != ctl_I && ctl != ctl_FRMR && buflen(bp) != 0) {
frmr(axcb, W+X, control, iscmd);
return bp;
}
/* Process the frame based on control field type */
if (ctl>0) {
if (ctl<4) ch = state_tables[ctl-1]
[ ( iscmd ? 1 : 0) ]
[ ( ctl_PF ? 1 : 0)];
else ch = state_tableu[ctl-4];
}
else if (ctl == -1) ctl = ctl_SABM+1;
if (ctl <= ctl_REJ) {
/* S frames: process the N(R), then respond
via state table nothing tricky here */
axcb->window=l2_window(axcb->parms);
procnr(axcb, control, iscmd);
/* I frames: process the receive-sequence */
/* number N(R), followed by the I field. */
if (ctl == ctl_I) {
bp = proci(axcb, bp, control, iscmd);
}
}
else if (ctl <= ctl_DM) {
/* U frames: respond via state table except
for SABM and UA, which require
a little special handling. */
if (ctl == ctl_UA)
if (axcb->state == 2) /* Update the link version on connect */
axcb->version = rxversion;
}
else if (ctl == ctl_SABM) {
axcb->iface = iface;
setpath(axcb, &adr[1], 1, numadrm); /* Reset Path */
link_reset(axcb); /* Reset the link */
axcb->version = rxversion; /* Update the link version */
idle_t1(axcb, 1); /* Start t3 running */
(void)(*axcb->s_upcall)(axcb,0,0);
}
else /* Reject bad control field */
frmr(axcb, W, control, iscmd);
if (ch != NULL) /* I frames handled elsewhere */
respond(axcb, ch, control, iscmd);
return bp; /* Free the frame, will be NULL if proci accepted data */
}
/* respond -- act on the received frame via the passed state table
*/
respond(axcb, ch, rctl, rcmd)
register struct axcb *axcb; /* Link */
struct change *ch; /* State table pointer */
unsigned char rctl; /* Received control field */
char rcmd; /* Received frame was a command */
{
static int st, acts;
static int sctl;
static unsigned char pf;
puthex2("respond",ch,"ctl",rctl);
pf=0;
st = axcb->state -1; /* State-table index */
acts = ch[st].acts; /* Get action flags */
/* Reset the t1 timer and restore the retry count (n2) if specified */
if (acts & RSTT1) idle_t1(axcb, 1);
/* Here if a resulting frame is to be transmitted */
sctl=ch[st].ctl;
if (sctl == 255) sctl= -1; /* Just incase chars are unsigned/tm */
if (sctl != -1) {
/* FRMR handled specially */
if (sctl == FRMR) {
frmr(axcb, -1, 0, 0);
return;
}
/* If I frame transmission specified, check that there is data on
* the transmit queue. If not, change to S frame or nothing, based
* on the state of the RESPOND action flag.
*/
if (!(sctl & 1))
if (axcb->iqueue == NULL)
#if 0
if (acts & RESPOND)
sctl = (axcb->flags & BUSY) ? RNR : RR;
else
sctl = -1;
#endif
sctl = ((acts & RESPOND) ?
((axcb->flags & BUSY) ? RNR : RR) : -1);
/* Set P/F bit from received frame or action flag */
if (axcb->version == V1 || rcmd) pf = rctl & PF;
pf |= acts & PF;
}
/* Send the frame, change the state and all that dreck */
actionl2(axcb, ch[st].newstate, sctl, pf, acts);
}
/* setpath -- update axcb path from received address field */
setpath(axcb, addr, swapdigi, alenx)
register struct axcb *axcb; /* Link to update */
struct ax25_addr *addr; /* received address field */
char swapdigi; /* 1 if digis need to be reverse order */
int alenx;
{
static int i, j, alen;
alen = alenx;
/* Store path in axcb */
axcb->alen = alen;
if (!alen) return;
/* Clear all address-extension bits, and set the last */
for (i = 0; i < alen; i++) {
j=i;
if (swapdigi && i>0) j=alen-i;
bcopy(addr[i].call, axcb->path[j].call, ALEN);
axcb->path[j].ssid = (addr[i].ssid & ~E );
if (i>0) axcb->path[j].ssid ^= REPEATED; /* Toggle Repeated bit*/
}
if (i>1) axcb->path[alen-1].ssid |= E; /* Set the last extension bit */
else axcb->myaddr.ssid |= E;
}
/* link_reset -- stops the timers, clears the flags and resets the
* sequence numbers for the link.
*/
link_reset(axcb)
register struct axcb *axcb; /* Link */
{
axcb->vs = axcb->ns = axcb->nr = 0;
axcb->flags &= ~INVNS;
kill(axcb->t1); /* Kill all timers */
kill(axcb->t2);
kill(axcb->t3);
kill(axcb->t20);
free_queue(&axcb->iqueue); /* Throw out any outstanding tx or rx data */
free_pkt(axcb->rcvq);
axcb->icnt = 0;
axcb->rcvcnt = 0;
}
/* axconnect -- initiate connect attempt on link (also known as a
* "local start command" in the protocol spec). Returns 1 if OK, else 0
*/
axconnect(axcb)
register struct axcb *axcb;
{
if (axcb->alen == 0) return 0; /* No path set! */
axcb->n2cnt = (axcb->parms->retry >> 1);
if (axcb->n2cnt == 0) axcb->n2cnt = 1;
/* Send a SABM command, transition to state 2, start t1 */
actionl2(axcb, 2, SABM, PF, CMD+RSTT1+SETT1);
return 1;
}
void
setcalls(p,calls)
struct datastr *p;
register struct ax25_addr *calls;
{
static int j;
for (j=0;j<ALEN;j++) {
bappch(p,calls->call[j]);
}
bappch(p,calls->ssid);
}
struct datastr *
setaddr(axcb,ctl,size)
register struct axcb *axcb;
int ctl,size;
{
static struct datastr *p;
static char i;
/* Room for address and control and extra space needed by caller */
p=new_buffer( 1 + size + (axcb->alen+1) * AXALEN);
if (p==NULL) return NULL;
setcalls(p,&axcb->path[0]);
setcalls(p,&axcb->myaddr);
for (i=1;i<axcb->alen;i++) setcalls(p,&axcb->path[i]);
bappch(p,ctl);
return p;
}
/* actionl2 -- takes action on the link.
*/
actionl2(axcb, newstatex, sctlx, pf, acts)
register struct axcb *axcb; /* Link */
char newstatex; /* New state, or 0 if no change */
int sctlx; /* Control field to send */
char pf; /* P/F bit needed */
char acts; /* Action flags */
{
static char oldstate, newstate;
static int sctl;
puthex2("actionl2",sctlx,"newst",newstate);
newstate=newstatex;
oldstate = axcb->state; /* Save old state */
/* Reset link if connecting */
if ((sctl=sctlx) == SABM) {
link_reset(axcb);
axcb->version = axcb->parms->version; /* Reset version */
}
/* State transition. Set new state, then call state-change upcall if
* going into an information-transfer state (i.e. state > 4) from a
* setup state (i.e. state < 5)
*/
if (newstate != 0) {
axcb->state = newstate;
if (oldstate < 5 && newstate > 4) {
/* Return busy indication if no upcall vector or upcall function
* returns error indication
*/
if ( !(*axcb->s_upcall)(axcb, oldstate, newstate)) {
sctl = DM;
newstate = axcb->state = 1;
} else {
/* Now that state-change upcall has been made, perform transmit upcall
*/
(*axcb->t_upcall)(axcb);
}
}
}
/* Transmission handler. Set C bits for command/response/none (V1) */
if (sctl != -1 && !axcb->t2) /* MAY BE BUG 3/20 from 303 */ {
axcb->myaddr.ssid &= ~C;
axcb->path[0].ssid &= ~C;
if (axcb->version >= V2)
if (acts & CMD)
axcb->path[0].ssid |= C;
else
axcb->myaddr.ssid |= C;
/* If I frame, call the sending function and quit */
if (!(sctl & 1) && (axcb->iqueue != NULL)) {
sendi(axcb);
return;
}
/* If S frame, merge receive-sequence variable into control field */
if ((sctl & 3) == S) sctl |= (axcb->nr << 5);
if (pf) sctl |= PF; /* Put P/F bit in */
/* Call interface driver to transmit the frame */
(*axcb->iface->send)(axcb->iface,setaddr(axcb,sctl,0));
}
/* If specified by action flag, start/restart t1 running */
if (acts & SETT1) recovery(axcb);
else sendi(axcb); /* Send I frames if possible */
/* If going disconnected, clear the link */
if (axcb->state < 2) {
link_reset(axcb);
axcb->flags = 0;
/* Inform state-change upcall function of disconnect */
if (oldstate > 1) (*axcb->s_upcall)(axcb, oldstate, newstate);
}
}
/* sendi - sends I frame(s). Sends up to axcb->maxframe frames from
* the transmit queue
*/
sendi(axcb)
register struct axcb *axcb; /* Link */
{
static struct datastr *bp;
static struct datastr *dp;
static int i;
static char ctl;
if (axcb->iqueue == NULL) return; /* Nothing to send */
if ((axcb->t1 != NULL) || (axcb->t2 != NULL) || (axcb->state<5)) return;
/* Can't send I frames if t1 or t2 running or not connected */
axcb->vs = axcb->ns; /* Init send variable */
bp = axcb->iqueue; /* Point to top of queue */
axcb->myaddr.ssid &= ~C; /* I frame is never a response */
if (axcb->version == V1)
axcb->path[0].ssid &= ~C;
else /* Make it a command */
axcb->path[0].ssid |= C;
/* Frame-send loop */
for (i = 0; i < axcb->parms->maxframe; i++, bp = bp->next) {
puthex2("txfrm",axcb->parms->maxframe,"",bp);
if (bp == NULL) break; /* Quit at end of queue */
ctl=(axcb->nr << 5) | (axcb->vs << 1); /* Form control field */
/* Make a copy of the data, we might have to send it again */
dp = dup_pkt(bp);
if ((axcb->iface->send == NULL) || !dp) break; /* Can't Send */
dp= binsert( setaddr(axcb,ctl,0), dp );
(*axcb->iface->send)(axcb->iface,dp);
axcb->vs = (axcb->vs + 1) & 7; /* Increment send variable */
}
recovery(axcb); /* Start the t1 timer */
}
/* procnr -- process the N(R) value of a received I or S frame */
procnr(axcb, control, iscmd)
register struct axcb *axcb; /* Link */
int control; /* Received control field */
char iscmd; /* 1 if received frame is a command */
{
static char rs, top, acked;
static struct datastr *bp;
acked=0;
/* Don't bother if we are'nt connected */
if (axcb->state < 5)
return;
/* Break the sequence number out of the control field */
rs = ctl_NR; /* (control >> 5) & 7; */
/* Determine the proper highest and lowest acceptible sequence values
* If the N(S) value (lowest outstanding frame number) is greater than
* or equal to V(S) (highest outstanding frame number), adjust V(S) to
* a value greater than N(S) by adding 8 to it and to R(S). (This
* happens when the modulo-8 sequence number "rolls over" to 0 during
* transmission.)
*/
if (axcb->vs >= axcb->ns)
top = axcb->vs;
else {
top = axcb->vs + 8;
if (rs < axcb->ns)
rs += 8;
}
/* If R(S) isn't within the acceptible range, reject the frame */
if (rs < axcb->ns || rs > top) {
frmr(axcb, Z, control, iscmd);
return;
}
/* For each acknowledged frame, increment N(S), yank the acked frame
* off the tx queue, and reduce the queue data count.
*/
while (rs > axcb->ns) {
axcb->ns++;
if (axcb->iqueue != NULL) {
bp = axcb->iqueue;
axcb->icnt -= buflen(bp);
axcb->iqueue = bp->next;
free_pkt(bp);
}
/* If a frame (or frames) is being acked, perform state-change stuff */
acked = 1;
}
/* Normalize N(S) modulo 8 */
axcb->ns &= 7;
/* If frames were acked and the tx window is open, notify the transmit
* upcall handler
*/
if (acked || axcb->window > axcb->icnt) {
respond(axcb, (axcb->version == V1) ? val_nsv1 : val_ns, 0, 0);
(*axcb->t_upcall)(axcb);
}
}
/* proci -- process the send-sequence number and I field of received
* frames
*/
struct datastr *
proci(axcb, bpx, controlx, iscmd)
register struct axcb *axcb; /* Link */
struct datastr *bpx; /* Received frame */
int controlx; /* Received control field */
char iscmd; /* 1 if received frame was a command */
{
static int pid, c;
static int control;
static char vs;
static struct datastr *bp1, *bp;
void t2_timeout();
bp=bpx;
control=controlx;
/* Don't bother if not connected */
if (axcb->state < 5) return bp;
#if 0
/* If I field is too big, reject the frame */
/* allow upto 4 extra bytes, PID and a trim 3 bytes for X.25 level 3 */
if (buflen(bp) > axcb->parms->framesize+4) {
frmr(axcb, Y, control, iscmd); /* Ham Devices don't do this */
return bp;
}
#endif
/* Ignore received frames if we are busy (rx queue full) */
if (!(axcb->flags & BUSY)) {
/* Get the PID field */
if ( (pid=bgetch(&bp)) == -1)
frmr(axcb, W+Y, control, iscmd);
/* Break out the N(S) value and reset the "invalid N(S)" flag */
vs = ctl_NS; /* (control >> 1) & 7; */
axcb->flags &= ~INVNS;
/* If this frame is not the expected one, set "invalid N(S)" */
if (vs != axcb->nr)
axcb->flags |= INVNS;
/* Save control field for delayed response */
axcb->rctl = control;
/* If this is expected frame, accept it */
if (vs == axcb->nr) {
axcb->rpid = pid; /* Update received PID */
axcb->nr = (axcb->nr + 1) & 7; /* Increment our N(R) */
if ((c=buflen(bp)) > 0) { /* Process data in frame */
bp1 = axcb->rcvq;
/* Update receive queue count */
axcb->rcvcnt += c;
/* Update window Size based on free memory */
axcb->window=l2_window(axcb->parms);
/* If receive window is now closed, perform go-busy routine */
if (axcb->rcvcnt >= axcb->window) {
axcb->flags |= BUSY;
c = go_busy[axcb->state-1].newstate;
/* Enter busy state */
if (c != 0)
axcb->state = c;
}
/* this may be converting frames in to a data stream, should be done in the
user module not a level 2 function!!! [append, next line] w2vy 10/86 */
axcb->rcvq=binsert(axcb->rcvq, bp);
/* Put data on the rx queue */
bp = NULL; /* Buffer isn't ours any more */
/* Always pass a revd frame to the upper layer w2vy */
(*axcb->r_upcall)(axcb);
}
reset_t3(axcb); /* Link activity; reset t3 */
}
}
/* If delayed-response is in effect, start t2 timer running */
/* kill(axcb->t2); /* Incase it was running */
queue(&axcb->t2,t2_timeout,axcb->parms->resptime,axcb);
return bp;
}
/* l2_window - Return what window size should be based on how much
/* memory the switch has left, max size is maxframe*framesize */
int
l2_window(parms)
register struct ax25_parms *parms;
{
static int i;
i=parms->maxframe * parms->framesize;
switch (spclev()) {
case FINE: return i; /* Whole window */
case LIMITED: return (i>>1); /* Only 1/2 */
case CRITICAL: return (0); /* Nothing! */
}
}
/* frmr -- reject bad received frame
* "errtyp" should be -1 to repeat the previous FRMR frame
*/
frmr(axcb, errtyp, control, iscmd)
register struct axcb *axcb; /* Link */
char errtyp; /* Error type for FRMR I field */
char control; /* Received control field */
char iscmd; /* 1 if received frame is command */
{
static struct datastr *bp;
/* static char info[3]; */
static char *ch;
static char newstate;
ch = axcb->info;
newstate=0;
if (errtyp != -1) { /* Form new FRMR I field */
newstate = 3; /* Go to frame reject state */
/* Form FRMR I field */
*ch++ = errtyp;
*ch = 0;
if (iscmd) *ch |= PF;
*ch++ |= (axcb->nr << 5) + (axcb->ns << 1);
*ch = control;
ch = axcb->info;
}
/* Make an datastr of the FRMR data and send it */
bp = setaddr(axcb,FRMR,3);
bappch(bp,*ch++);
bappch(bp,*ch++);
bappch(bp,*ch);
(*axcb->iface->send)(axcb->iface,bp);
actionl2(axcb, newstate, -1, 0, 0); /* Transition to FRMR state */
}
/* t1_timeout -- t1 timer handler. On timeout:
* 1) Start t3 timer if not V1 protocol
* 2) Decrement retry (N2) count if not 0
* 3) If N2 decremented to 0, respond via "N2 exceeded" state table,
* otherwise, respond via "t1 expired" state table
*/
void
t1_timeout(axcb)
register struct axcb *axcb; /* Link */
{
idle_t1(axcb, 0);
if (axcb->n2cnt)
if (--axcb->n2cnt == 0) {
respond(axcb, n2_exceeded, 0, 0);
return;
}
respond(axcb, (axcb->version == V1) ? t1_expv1 : t1_exp, 0, 0);
}
/* t2_timeout -- t2 timer handler. On timeout, if link "invalid N(S)
* received" flag is set, respond via "invalid N(S)" state table, otherwise
* respond via "i frame" state table.
*/
void
t2_timeout(axcb)
register struct axcb *axcb; /* Link */
{
(*axcb->r_upcall)(axcb);
if (axcb->flags & INVNS)
respond(axcb,(axcb->version == V1) ? inv_nsv1 : inv_ns,
axcb->rctl, axcb->rcmd);
else
respond(axcb, (axcb->rctl & PF) ? i_cmdp : i_cmd,
axcb->rctl, axcb->rcmd);
}
/* t3_timeout -- t3 timer handler. On timeout, respond via "t3 expired"
* state table.
*/
void
t3_timeout(axcb)
register struct axcb *axcb; /* Link */
{
if (axcb->version == V1) close_ax25(axcb); /* Disconnect this guy */
else respond(axcb, t3_exp, 0, 0); /* Poll or give up */
}
/* recovery -- initializes (starts) t1 timer and stops t3 timer.
* t1 timer period is calculated by:
* p = (2*n + 1) * f
* where p=period in seconds, n = number of digi addresses in the link
* path, and f=frack
*/
/* static .. what is a static function?? /tm */
recovery(axcb)
register struct axcb *axcb; /* Link */
{
static int i, j;
kill(axcb->t3);
i=axcb->alen;
if (i>2) i -= 2; /* Subtract off the switch call and address */
j = axcb->parms->retry - axcb->n2cnt + 1;
i=(i + (j<axcb->n2cnt ? j : axcb->n2cnt)) * axcb->parms->frack + rnd(3);
#if 0
i = ( 2 *(i-1) +1) * (axcb->parms->frack *
(axcb->parms->retry - axcb->n2cnt + 1)) + rnd(3);
#endif
queue(&axcb->t1,t1_timeout,i,axcb);
}
/* idle_t1 -- stops the t1 timer, optionally resetting the retry (N2) count.
* starts the inactive link (t3) timer if the link isn't using V1 protocol
*/
idle_t1(axcb, reset)
register struct axcb *axcb; /* Link */
char reset; /* 1 to reset retry count */
{
kill(axcb->t1);
if (reset)
axcb->n2cnt = axcb->parms->retry;
reset_t3(axcb);
}
/* reset_t3 - restart t3 (link activity occurred) */
reset_t3(axcb)
register struct axcb *axcb; /* Link */
{
static int c;
/* kill(axcb->t3); */
c = axcb->parms->check;
if (axcb->am_dce) c += 3;
queue(&axcb->t3,t3_timeout,c,axcb);
}